package main

import (
	"context"
	"k8s-operator-test/k8s"
	"log"
	"os"

	"github.com/gin-gonic/gin"
	apiAppv1 "k8s.io/api/apps/v1"
	apiCorev1 "k8s.io/api/core/v1"
	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/intstr"
	"k8s.io/client-go/kubernetes"
)

const Version = "v1alpha"

var namespace string = "testing"

var kubeConfigFile string = "/root/.kube/config" //Default auth config

var k8sClient *kubernetes.Clientset

func main() {

	app := NewRouter()

	if err := app.Run(":9876"); err != nil {
		log.Fatalln(err)
	}

}

func NewRouter() *gin.Engine {

	app := gin.New()

	app.GET("/nodes", ListNodes)

	app.GET("/namespaces", ListNamespace)

	app.GET("/deployments", ListDeployment)

	app.GET("/services", ListService)

	app.GET("/pods", ListPods)

	app.POST("/create/deployment", CreateDeployment)

	app.POST("/create/service", CreateService)

	app.POST("/delete/DeploymentAndService", DeleteDeploymentAndService)

	return app
}

// ListNodes 获取所有节点
func ListNodes(g *gin.Context) {

	log.Println(g.FullPath())

	nodes, err := k8sClient.CoreV1().Nodes().List(context.Background(), metav1.ListOptions{})
	if err != nil {
		g.AbortWithStatusJSON(500, err)
		return
	}
	g.JSON(200, nodes)
}

// ListNamespace 获取所有命令空间
func ListNamespace(g *gin.Context) {

	log.Println(g.FullPath())

	ns, err := k8sClient.CoreV1().Namespaces().List(context.Background(), metav1.ListOptions{})
	if err != nil {
		g.AbortWithStatusJSON(500, err)
		return
	}
	g.JSON(200, ns)
}

func ListPods(g *gin.Context) {

	log.Println(g.FullPath())

	ns := g.Query("ns")

	dps, err := k8sClient.CoreV1().Pods(ns).List(context.Background(), metav1.ListOptions{})
	if err != nil {
		g.AbortWithStatusJSON(500, err)
		return
	}
	g.JSON(200, dps)
}

func ListDeployment(g *gin.Context) {

	log.Println(g.FullPath())

	ns := g.Query("ns")

	dps, err := k8sClient.AppsV1().Deployments(ns).List(context.Background(), metav1.ListOptions{})
	if err != nil {
		g.AbortWithStatusJSON(500, err)
		return
	}
	g.JSON(200, dps)
}

func ListService(g *gin.Context) {

	log.Println(g.FullPath())

	ns := g.Query("ns")

	svc, err := k8sClient.CoreV1().Services(ns).List(context.Background(), metav1.ListOptions{})
	if err != nil {
		g.AbortWithStatusJSON(500, err)
		return
	}
	g.JSON(200, svc)
}

func CreateDeployment(g *gin.Context) {

	log.Println(g.FullPath())

	var replicas int32 = 2
	var AutomountServiceAccountTokenYes bool = true

	deployment := &apiAppv1.Deployment{
		TypeMeta: metav1.TypeMeta{
			Kind:       "Deployment",
			APIVersion: "apps/v1",
		},
		ObjectMeta: metav1.ObjectMeta{
			Name:      "k8s-test-stub",
			Namespace: "testing",
			Labels: map[string]string{
				"app": "k8s-test-app",
			},
			Annotations: map[string]string{
				"creator": "k8s-operator-test",
			},
		},
		Spec: apiAppv1.DeploymentSpec{
			Selector: &metav1.LabelSelector{
				MatchLabels: map[string]string{
					"app": "k8s-test-app",
				},
			},
			Replicas: &replicas,
			Template: v1.PodTemplateSpec{
				ObjectMeta: metav1.ObjectMeta{
					Labels: map[string]string{
						"app": "k8s-test-app",
					},
				},
				Spec: v1.PodSpec{
					Containers: []apiCorev1.Container{
						{
							Name:  "nginx",
							Image: "nginx:alpine",
						},
					},
					RestartPolicy:                "Always",
					DNSPolicy:                    "ClusterFirst",
					NodeSelector:                 nil,
					ServiceAccountName:           "",
					AutomountServiceAccountToken: &AutomountServiceAccountTokenYes,
				},
			},
			Strategy: apiAppv1.DeploymentStrategy{
				Type: "RollingUpdate",
				RollingUpdate: &apiAppv1.RollingUpdateDeployment{
					MaxUnavailable: &intstr.IntOrString{
						Type:   intstr.String,
						IntVal: 0,
						StrVal: "25%",
					},
					MaxSurge: &intstr.IntOrString{
						Type:   intstr.String,
						IntVal: 0,
						StrVal: "25%",
					},
				},
			},
		},
	}

	dp, err := k8sClient.AppsV1().Deployments("testing").Create(context.Background(), deployment, metav1.CreateOptions{})
	if err != nil {
		g.AbortWithStatusJSON(500, err)
		return
	}
	g.JSON(200, dp)
}

func CreateService(g *gin.Context) {
	log.Println(g.FullPath())

	svc := &apiCorev1.Service{
		TypeMeta: metav1.TypeMeta{
			Kind:       "Service",
			APIVersion: "v1",
		},
		ObjectMeta: metav1.ObjectMeta{
			Name:      "k8s-test-stub",
			Namespace: "testing",
			Labels: map[string]string{
				"app": "k8s-test-app",
			},
			Annotations: map[string]string{
				"creator": "k8s-test-operator",
			},
		},
		Spec: apiCorev1.ServiceSpec{
			Ports: []apiCorev1.ServicePort{
				{
					Name:     "http",
					Protocol: "TCP", //注意这里必须为大写
					Port:     80,
					TargetPort: intstr.IntOrString{
						Type:   intstr.Int,
						IntVal: 80,
						StrVal: "",
					},
					NodePort: 0,
				},
			},
			Selector: map[string]string{
				"app": "k8s-test-app",
			},
			Type: "NodePort",
		},
	}

	svs, err := k8sClient.CoreV1().Services("testing").Create(context.Background(), svc, metav1.CreateOptions{})
	if err != nil {
		g.AbortWithStatusJSON(500, err)
		return
	}
	g.JSON(200, svs)
}

func DeleteDeploymentAndService(g *gin.Context) {
	err := k8sClient.AppsV1().Deployments("testing").Delete(context.Background(), "k8s-test-stub", metav1.DeleteOptions{})
	if err != nil {
		g.AbortWithStatusJSON(500, err)
		return
	}
	err = k8sClient.CoreV1().Services("testing").Delete(context.Background(), "k8s-test-stub", metav1.DeleteOptions{})
	if err != nil {
		g.AbortWithStatusJSON(500, err)
		return
	}
	g.String(200, "Deployment 和 Service 删除成功")
}

func init() {
	_, ferr := os.Stat(kubeConfigFile)
	if ferr != nil {
		kubeConfigFile = ""
	}
	var err error
	k8sClient, err = k8s.CreateK8sApiServerClient("", "", kubeConfigFile)
	if err != nil {
		log.Fatalf("Create K8s ApiServer clientsets error: %v", err)
	}
}
